#!/bin/sh

#-------------------------------------------------------------------------------
# restore.sh
# 
# This shell script is invoked to perform a restore of the HSC backup data.
# This script should be executed every time the system reboots.  If no
# "indicator" file is present, the script exits and no file restoration is done.
# 
# Usage: 'restore'
#
# Return Codes:
# 1 - Error mounting the upgrade partition
# 2 - Error Copying from the media
# 3 - Archive not present
# 4 - Error unmounting the media
# 5 - Other Errors
# 6 - DVD drive failure
# 7 - No media inserted
# 8 - Unformatted media
# 9 - Incorrect label on media
# 10 - tar error extracting relative to working directory
# 11 - unable to create staging directory
# 12 - no need to run a restore
# 13 - unable to generate the excluded shared object file list
# 14 - tar error extracting non-*.so files relative to / dir
# 15 - staged file move/copy error

#-------------------------------------------------------------------------------
# directory and filename which records the backup actions.
#-------------------------------------------------------------------------------
LOGDIR=/var/hsc/log
LOG=$LOGDIR/restore.log

LOG_ERROR_LOG=/tmp/restore.log
ERROR_LOG=/tmp/archive.log

# stdout of 'mount' command directed to /tmp/mount_output+PID
MOUNT_OUTPUT=/tmp/mount_output$$

#-------------------------------------------------------------------------------
# mount point: the mount point where the backup data is contained
#-------------------------------------------------------------------------------
MOUNTPOINT=/mnt/cdrom

#-------------------------------------------------------------------------------
# the filename of the backup archive
#-------------------------------------------------------------------------------
ARCHIVENAME=backuphdr.tgz
ARCHIVE=$MOUNTPOINT/$ARCHIVENAME

#-------------------------------------------------------------------------------
# the (hard drive) media mount point where the indicator file, created by the
# CD re-install process, is stored.  There should be an entry for this
# mountpoint in /etc/fstab
#-------------------------------------------------------------------------------
UPGRADE_MOUNTPOINT=/mnt/upgrade

#-------------------------------------------------------------------------------
# the indicator file. If it exists, execute 'tar' cmd to restore the backup data
#-------------------------------------------------------------------------------
INDFILE=iqybcrit.dat
IQYBCRIT=$UPGRADE_MOUNTPOINT/$INDFILE

#-------------------------------------------------------------------------------
# Flag to indicate a critical error has occurred during 'tar' file processing
#-------------------------------------------------------------------------------
ARCHIVEFAIL=0

 
#
# common exit point for script
#
exit_cleanup() {
    rm -f $MOUNT_OUTPUT
    umount $UPGRADE_MOUNTPOINT
    
    if [ $ARCHIVEFAIL -ne 0 ]; then
         echo "!potential critical archive failure!" >> $LOG
         echo "archive failure error code is: $ARCHIVEFAIL" >> $LOG
         echo "task completed on `date`, return status = 99" >> $LOG
         exit 99
    else
         echo "task completed on `date`, return status = $1" >> $LOG
    fi
    exit $1
}  



# Check if the directory for the log file exists.
if [ ! -d $LOGDIR ]; then
     echo "=================================================================" > $LOG_ERROR_LOG
     echo -e "Restore task log for `date`." >> $LOG_ERROR_LOG
     echo "Restore task log directory, <$LOGDIR>, does not exist. Program exiting" >> $LOG_ERROR_LOG
     exit 5
fi


# Just in case we have NLS troubles reading system information...
LANG=en_US
export LANG


# Start log to record restore actions.
echo -e "Restore log for `date`\n" > $LOG


#-------------------------------------------------------------------------------
# Mount the media where the indicator file should be located
#-------------------------------------------------------------------------------
mount -v $UPGRADE_MOUNTPOINT > $MOUNT_OUTPUT 2>&1
if [ $? -ne 0 ]; then

   #----------------------------------------------------------------------------
   # already mounted?  Not an error, but a non-zero return code.  Continue
   #----------------------------------------------------------------------------
   if grep "already mounted" $MOUNT_OUTPUT; then
        echo "The mountpoint, $UPGRADE_MOUNTPOINT, is already mounted.  Continuing..." >> $LOG

   #----------------------------------------------------------------------------
   # other error?  Game over.
   #----------------------------------------------------------------------------
   else
        echo "The mountpoint, $UPGRADE_MOUNTPOINT, cannot be mounted.  Error is $?" >> $LOG
        exit_cleanup 1
   fi
fi

#-------------------------------------------------------------------------------
# good mount of output device, continue
#-------------------------------------------------------------------------------
echo "partition with indicator file, $INDFILE, mounted at $UPGRADE_MOUNTPOINT." >> $LOG


#-------------------------------------------------------------------------------
# if IQYBCRIT.DAT doesn't exist, there is nothing to do
#-------------------------------------------------------------------------------
if [ ! -e $IQYBCRIT ]; then
      echo "$IQYBCRIT indicator file does not exist. Data restoration not required" >> $LOG
      echo -e "restore script exiting.\n" >> $LOG
      exit_cleanup 12
fi


#-------------------------------------------------------------------------------
# Check to see if the backup media (DVD) is already mounted
#-------------------------------------------------------------------------------
if grep -q "$MOUNTPOINT" /etc/mtab; then
      # Media is already mounted, unmount in preparation for (re-)'mount' cmd
     if ! umount -v $MOUNTPOINT >> $LOG 2>&1; then
          echo "Couldn't umount the media... exiting" >> $LOG
          exit_cleanup 4
     fi
fi

#-------------------------------------------------------------------------------
# Mount and check for existence of archive
#-------------------------------------------------------------------------------
#if mount -t udf -v $MOUNTPOINT > $MOUNT_OUTPUT 2>&1; then   # udf/dvd specific
if mount -v $MOUNTPOINT > $MOUNT_OUTPUT 2>&1; then
     echo "successfully mounted the backup media, continuing..." >> $LOG

# leave this test out since HSC does not do a specific DVD format
#       if !(chkudf /dev/hdc | grep -q -i "ACTBKP" 2>&1); then # udf/dvd specific
     false=0
     if false; then # floppy test
          echo "The media has an incorrect label... exiting" >> $LOG
          umount $MOUNTPOINT
          exit_cleanup 9
     elif [ ! -e $ARCHIVE ]; then
          echo "The backup archive is not on the restore media... exiting" >> $LOG
          umount $MOUNTPOINT
          exit_cleanup 3
     fi
     echo "backup archive file detected on media, continuing..." >> $LOG
else
     echo "Could NOT mount the media..." >> $LOG

     # Check for no media inserted. If this is the case, we're going to remove the
     # iqybcrit.dat file.  That file should never remain on the system unless the
     # product recovery CD was just used. The last thing the recovery CD process
     # does is prompt to insert the backup archive media.  Hence, if no media, no
     # need for recovery indicator flag.
     #
     # Using 'grep' here seems kinda unnecessary/risky. We should just key off
     # 'mount' cmd return codes instead...

     if grep -q -i "wrong major or minor number" $MOUNT_OUTPUT; then
          echo -e "Hardware failure on the DVD RAM drive... exiting\n" >> $LOG
          exit_cleanup 6
     elif grep -q -i "No medium found" $MOUNT_OUTPUT; then
          echo -e "No media in the DVD RAM drive... exiting\n" >> $LOG

          # Here's one place where we'll remove the indicator file. This
          # will hopefully catch the manufacturing process issue whereby
          # they are installing the pHMCs from the recovery CD, which
          # contains the indicator file, during the initial HMC install.
          # That file should not initially be on the system.  The 'no media'
          # return code from 'mount' cmd is 32.
          rm -f $IQYBCRIT

          exit_cleanup 7
     elif grep -q -i "wrong fs type" $MOUNT_OUTPUT; then
          echo -e "Wrong filesystem type, or unformatted media, or wrong media type... exiting\n" >> $LOG
          exit_cleanup 8
     else
          echo -e "Unknown error... exiting\n" >> $LOG
          exit_cleanup 5
     fi
fi

# If the file hmcConfigured exists then
# it is not a new install, the DVD containing
# backup data happens to be inserted in
new_install=1
if [ -f /opt/hsc/data/hmcConfigured ]; then
     new_install=0
fi


#-------------------------------------------------------------------------------
# Now do the actual restore from the archive
#-------------------------------------------------------------------------------
echo -e "starting file archive restore...\n" >> $LOG

#
# First thing to do is determine which files are shared objects that could 
# potentially be partially paged in the system.  Hence, a recurring read
# of that same library file could panic the system - in theory, of course.
# Rather than using the 'tar' command to restore those particular archive
# files, we'll be staging those files and using the 'mv' command.
#
# Construct a working/staging directory for pre/post processing 
#
WORKING_DIR=/tmp/restore/work
mkdir -p $WORKING_DIR
if [ $? -ne 0 ]; then
     umount -v $MOUNTPOINT >> $LOG 2>&1
     exit_cleanup 11
fi

#
# start with a clean error log
#
rm -f $ERROR_LOG
echo -e "begin file recovery error log for `date`\n" > $ERROR_LOG

#
# build the list of all files that have a '.so' extension
#
tar -tvzf $ARCHIVE | grep "\.so" | awk '{print $6}' > $WORKING_DIR/exclude.list 2>> $ERROR_LOG
if [ $? -ne 0 ]; then
     umount -v $MOUNTPOINT >> $LOG 2>&1
     exit_cleanup 13
fi
echo "special file processing list constructed, continuing..." >> $LOG

#
# Next step is to un-tar only the previously excluded files to the
# staging area.
#
tar -xvzf $ARCHIVE --files-from=$WORKING_DIR/exclude.list --directory=$WORKING_DIR >> $ERROR_LOG 2>&1
tarRC=$?
if [ $tarRC -ne 0 ]; then
     ARCHIVEFAIL=$tarRC
     echo "shared object 'tar' processing to working directory failed. Continuing..." >> $LOG
else
     echo "'tar' processing of shared objects to working directory successful." >> $LOG
fi

#
# Now un-tar all remaining files from the archive
#
tar -xvzPf $ARCHIVE --overwrite --exclude-from=$WORKING_DIR/exclude.list --exclude=/var/hsc/log/restore.log --exclude=/opt/hsc/bin/restore --exclude=/etc/init.d/hmcRestore >> $ERROR_LOG 2>&1
tarRC=$?
if [ $tarRC -ne 0 ]; then
     ARCHIVEFAIL=$tarRC
     echo "remaining 'tar' archive processing failed. Continuing..." >> $LOG
else
     echo "remaining 'tar' archive file processing completed successfully." >> $LOG
fi

#
# Flush memory to disk, just in case
#   
sync

#
# Assuming this far, all files have been restored from the archive BUT
# we have to (pseudo-atomically?) relocate the *.so files.  We do this
# by 1) 'cp' the archive file to the *same filesystem* as it's current
# existing, version, 2) 'rm' current version, then 3) 'mv' archived
# version to current version
#
let RESTORE_INDICATOR=0
CP_FILE=
MV_FILE=

# example: if archive file is '/tmp/file1.ext'...
# 1) copy '/tmp/restore/work/tmp/file1.ext' to '/tmp/file1.ext.stage',
# 2) move 'tmp/file1.ext.stage' to '/tmp/file1.ext'
#
# Note: Many of the *.so files will most likely be symbolic links, so
#       be sure NOT to follow them when copying
#

# Comment out for GA3 PTF 3
#for i in `cat $WORKING_DIR/exclude.list`
#do
#     cp -dp $WORKING_DIR$i $i.stage 2>> $ERROR_LOG
#     if [ $? -ne 0 ]; then
#          let RESTORE_INDICATOR=RESTORE_INDICATOR+1
#          CP_FILE=$CP_FILE:$i
#     fi
#   
#     mv -f $i.stage $i 2>> $ERROR_LOG
#     if [ $? -ne 0 ]; then
#          let RESTORE_INDICATOR=RESTORE_INDICATOR+1
#          MV_FILE=$MV_FILE:$i
#     fi
#done


#
# Cleanup any staged *.so files
#
rm -fr $WORKING_DIR


#
# Additional cleanup - there is the possibility that the directories under /home
# (all the users' dirs) may have been re-generated via this restore process.
# Unfortunately, if the directory itself was not part of the archive, it will
# have been created with uid/gid of root/root as part of un-taring the actual
# files in those directories. This is not good since the users will not be able
# to access their home dirs! Change ownership of those subdirectories to the
# corresponding userID.
#
for user in `echo /home/*`
do
     chown ${user##/home/} $user
done


#
# Also remove the old restore log file, if it exists, since it has been
# renamed and isn't really valid once a new restore has run anyway...
#
if [ -a /var/hsc/log/hscrestore.log ]; then
     rm -f /var/hsc/log/hscrestore.log
fi


if [ $RESTORE_INDICATOR -eq 0 ]; then
     echo -e "restore from archive was successful.\n" >> $LOG
   
     #----------------------------------------------------------------------------
     # remove the hmcConfigured if this is a new install
     # remove the indicator file
     #----------------------------------------------------------------------------
     if [ "$new_install" = "1" ]; then
          rm -f /opt/hsc/data/hmcConfigured
     fi
   
     rm -f $IQYBCRIT
     echo "restore indicator file removed from HMC" >> $LOG
else
     echo -e "restore from archive was NOT successful.\n" >> $LOG
     echo "restore indicator is: $RESTORE_INDICATOR" >> $LOG
     echo "copy file errors are: $CP_FILES" >> $LOG
     echo -e "move file errors are: $MV_FILES\n" >> $LOG
   
     ARCHIVEFAIL=127
     umount -v $MOUNTPOINT >> $LOG 2>&1
     exit_cleanup 15
fi


#-------------------------------------------------------------------------------
# unmount the restore media
#-------------------------------------------------------------------------------
if umount -v $MOUNTPOINT >> $LOG 2>&1; then
     exit_cleanup 0
else
     echo "Couldn't umount the media" >> $LOG
     exit_cleanup 4
fi
